package vision;

import geometrie.Matrice;
import geometrie.Point;
import geometrie.Point2D;
import geometrie.Transformation;
import scene.Facette3D;
import scene.Scene;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
 * Class qui gère les elements que leur seront montrer dans l'ecran. 
 * @author Manuel
 * @author Marcos
 * */
public class AfficheurScene implements Affichable {
	private Scene scene;
	private int dimU;
	private int dimV;
	private double taillePixel;
	private Camera camera;
	private List<ImageFacette> imagesFacettes;
	/**
	 * Constructeur du class
	 * @param scene La scene à afficher
	 * @param dimU Dimension horizontale
	 * @param dimV Dimension verticale
	 * @param taillePixel Combien d'unites dans Ref_Scene pour chaque pixel
	 */
	public AfficheurScene(Scene scene,
	                      int dimU, int dimV, double taillePixel) {
		this.scene=scene;
		this.dimU=dimU;
		this.dimV=dimV;
		this.taillePixel=taillePixel;
		imagesFacettes=new ArrayList<ImageFacette>();
	}
	
	/**
	 * Retourne l'ensemble des images de facettes 3D a afficher.
	 * L'ordre d'affichage est celui du parcours de l'iterateur.
	 * @return Le ensemble de facettes en coordonnes cartesiennes 2D (ordonne) 
	 */
	@Override
	public Iterator<ImageFacette> getImagesFacettes() {	
		imagesFacettes.clear();
		
		//Extraire les modeles a montre		
		for(int i = 0; i < scene.getModeles().size(); i++){
			Iterator<Facette3D> it = scene.getModeles().get(i).getFacettes();
			while(it.hasNext()){
				Point2D[] points = new Point2D[3];
				Facette3D f = it.next();
				for(int j = 0; j < 3; j++){					
					try {						
						Point p = f.getPoint()[j];
						//Matrice: Projection x Point[j] de Facette
						Matrice m = Matrice.multMatrice(camera.getProjection().getMatrice(),new Matrice(p));
						points[j] = new Point2D();
						if(camera.isPerspective()){
								points[j].set(dimU/2 + (1/taillePixel)*m.getAt(0,0)/(m.getAt(2,0)/m.getAt(3,0)) * Math.abs(m.getAt(3,0)-camera.getRef().getZCartesien())*1/30,dimV/2 - (1/taillePixel)*m.getAt(1,0)/(m.getAt(2,0)/m.getAt(3,0)) * Math.abs(m.getAt(3,0)-camera.getRef().getZCartesien())*1/30);
						}
						else{
							points[j].set(dimU/2 + (1/taillePixel)*m.getAt(0,0),dimV/2 - (1/taillePixel)*m.getAt(1,0));
						}
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}					
				}
				imagesFacettes.add(new ImageFacette(points,Point.distance(camera.getRef(), f.getBarycentre())));				
			}
		}
		//Ordonne de le plus petit a le plus grand.
		Collections.sort(imagesFacettes);
		//Inverser la liste.
		Collections.reverse(imagesFacettes);
		return imagesFacettes.iterator();
	}
	/**
	 * Il donne la noveau transformation de projection a Camera.
	 */
	@Override
	public void positionneCamera(Transformation t) {
		if(camera==null)
			camera=new Camera(dimU, dimV);
		camera.setProjection(t);
	}
	
	/**
	 * Met la camera en mode de projection a ortographique.
	 */
	@Override
	public void setToCameraOrthographique() {
		camera.makeParallele();
	}
	
	/**
	 * Met la camera en mode de projection perspective.
	 * @param angle l'angle d'ouverture de la camera.(degre)
	 */
	@Override
	public void setToCameraPerspective(int angle) {
		double rad = Math.toRadians(angle);
		double f = (1/Math.tan(rad/2));
		camera.makePerspective(f);
	}
	
}
